<!DOCTYPE html>
<html lang="en">
  <head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="author" content="Zhou Wei <zromyk@163.com>">
  <title>C++岗位面试知识</title>
  <link rel="shortcut icon" href="/favicon.ico">
  <link rel="stylesheet" href="/style/pure.css">
  <link rel="stylesheet" href="/style/main.css">
  <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.css">
  <script src='/style/latest.js?config=TeX-MML-AM_CHTML'></script>
  <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
  <script src='/style/Valine.min.js'></script>
  <link href="https://apps.bdimg.com/libs/highlight.js/9.1.0/styles/default.min.css" rel="stylesheet">
  <script src="https://apps.bdimg.com/libs/highlight.js/9.1.0/highlight.min.js"></script>
  <script>hljs.initHighlightingOnLoad();</script>
  <script src="https://cdn.geogebra.org/apps/deployggb.js"></script>
  <script src="https://cdn1.lncld.net/static/js/2.5.0/av-min.js"></script>
  <script src='/style/readTimes.js'></script>
</head>
<body>
  <div id="menu-background"></div>
  <div id="menu">
    <div class="pure-menu pure-menu-horizontal">
  <div id="menu-block">
    <ul class="pure-menu-list">
      <a class="pure-menu-heading" href="/index.html">ZROMYK</a>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/index.html">主页</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/archive/index.html">归档</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/download/index.html">下载</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/feedback/index.html">反馈</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/about/index.html">关于我</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="https://github.com/zromyk"><i class="fa fa-github" style="font-size:32px"></i></a>
</li>

    </ul>
  </div>
</div>

  </div>
  <div id="layout">
    <div class="content">
      <div id="content-articles">
  <h1 id="C++岗位面试知识" class="content-subhead">C++岗位面试知识</h1>
  <p>
    <span>2021-03-25</span>
    <span><span class="post-category post-category-c">C++</span></span>
    <span id="/public/article/Cpp岗位面试知识.html" class="leancloud_visitors" style="display:none" data-flag-title="C++岗位面试知识"></span>
  </p>
  <h2 id="_1">语言基础</h2>
<h6 id="1">1. 在有继承关系的父子类中，构建和析构一个子类对象时，父子构造函数和析构函数的执行顺序分别是怎样的？</h6>
<ul>
<li>先构造的后析构，后构造的先析构，它相当于一个栈，先进后出。</li>
<li>首先执行基类的构造函数，随后执行派生类的构造函数，当撤销派生类对象时，先执行派生类的析构函数，再执行基类的析构函数。</li>
<li><u>当基类含有带参数的构造函数时，派生类必须定义构造函数</u>，以提供把参数传递给基类构造函数的途径。</li>
<li>如果没有参数的话，<u>可以不定义派生类的构造函数</u>，除非你的派生类的构造函数要实现别的功能才需要定义。</li>
</ul>
<h6 id="2-virtual-virtual">2. 在有继承关系的类体系中，父类的构造函数和析构函数一定要申明为 virtual 吗？如果不申明为 virtual 会怎样？</h6>
<ul>
<li>构造函数不能为虚函数；</li>
<li>析构函数必须申明为虚函数。<ul>
<li>原因：基类对象的指针操作派生类对象时，防止析构函数只调用基类的，而不调用派生类的。</li>
</ul>
</li>
</ul>
<h6 id="3-c-c">3. 什么是 C++ 多态？C++ 多态的实现原理是什么？</h6>
<ul>
<li><strong>静态多态</strong>就是重载，因为在编译期决议确定，所以称为静态多态。在编译时就可以确定函数地址。</li>
<li><strong>动态多态</strong>就是通过继承重写基类的虚函数实现的多态，因为实在运行时决议确定，所以称为动态多态。运行时在虚函数表中寻找调用函数的地址。</li>
</ul>
<h6 id="4">4. 什么是虚函数？虚函数的实现原理是什么？</h6>
<ul>
<li><strong>虚函数：</strong> 实现类的多态性。</li>
<li><strong>关键字：</strong>虚函数；虚函数的作用；多态性；多态公有继承；动态联编；</li>
<li>C++中的虚函数的作用主要是实现了多态的机制。基类定义虚函数，子类可以重写该函数；在派生类中对基类定义的虚函数进行重写时，需要在派生类中声明该方法为虚方法。</li>
<li>如果使用了 <strong>virtual</strong> 关键字，程序将根据 <u>引用 或 指针</u> 指向的 <strong>对象类型</strong> 来选择方法，否则使用 <strong>引用类型或指针类型</strong> 来选择方法。</li>
</ul>
<h6 id="5">5. 什么是虚表？虚表的内存结构布局如何？虚表的第一项（或第二项）是什么？</h6>
<h6 id="6-d-b-cb-cabcmmd">6. 菱形继承（类 D 同时继承 B 和 C，B 和 C又继承自A）体系下，虚表在各个类中的布局如何？如果类B和类C同时有一个成员变量m，m如何在D对象的内存地址上分布的？是否会相互覆盖？</h6>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">class A                      { public: int dataA; };
class B : public A           { public: int dataB; };
class C : public A           { public: int dataC; };
class D : public B, public C { public: int dataD; };
class E : public C, public B { public: int dataE; };

class D size(20):                  class E size(20):
        +---                                +---
 0      | +--- (base class B)       0      | +--- (base class C)
 0      | | +--- (base class A)     0      | | +--- (base class A)
 0      | | | dataA                 0      | | | dataA
        | | +---                           | | +---
 4      | | dataB                   4      | | dataC
        | +---                             | +---
 8      | +--- (base class C)       8      | +--- (base class B)
 8      | | +--- (base class A)     8      | | +--- (base class A)
 8      | | | dataA                 8      | | | dataA
        | | +---                           | | +---
12      | | dataC                  12      | | dataB
        | +---                             | +---
16      | dataD                    16      | dataE
        +---                               +---
</code></span></code></pre>
<h3 id="cc">C/C++语言基础</h3>
<h4 id="1-cccc">1. C++语言特点、C++语言特点、C和C++的区别</h4>
<h4 id="2">2. 头文件、变量、指针、运算符、数组、函数、结构体、传值方式</h4>
<h4 id="3-staticconst-nullptr-define">3. static、const、 nullptr、 ++、 define</h4>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">const int * pcint;  // 常量指针，指针指向的对象的值不可以修改
int * const cpint;  // 指针常量，指针指向的地址不可以修改
</code></span></code></pre>
<h5 id="4-new-malloc">4. new 和 malloc 区别</h5>
<div class="pure-table-scrollable"><table class="pure-table pure-table-horizontal">
<thead>
<tr>
<th></th>
<th>new / delete</th>
<th>malloc / free</th>
</tr>
</thead>
<tbody>
<tr>
<td>属性</td>
<td>C++ 关键字，需要编译器支持。</td>
<td>库函数，需要头文件支持。</td>
</tr>
<tr>
<td>参数</td>
<td>new 操作符申请内存分配时无须指定内存块的大小，编译器会根据类型信息自行计算。</td>
<td>malloc 需要显式地指出所需内存的尺寸。<br /><span style="overflow-x: auto; max-width:100%; display:inline;"><code>void malloc(size_t size)</code></span></td>
</tr>
<tr>
<td>返回类型</td>
<td>new 操作符内存分配成功时，返回的是对象类型的指针，类型严格与对象匹配，无须进行类型转换，故 new是符合类型安全性的操作符。</td>
<td>malloc 内存分配成功则是返回void * ，需要通过强制类型转换将 void* 指针转换成我们需要的类型。</td>
</tr>
<tr>
<td>分配失败</td>
<td>new 内存分配失败时，会抛出 <strong>bac_alloc</strong> 异常。</td>
<td>malloc 分配内存失败时返回 NULL。</td>
</tr>
<tr>
<td>自定义类型</td>
<td><strong>new</strong> 会先调用 <strong>operator new</strong> 函数，申请足够的内存（通常底层使用malloc实现）。然后调用类型的构造函数，初始化成员变量，最后返回自定义类型指针。delete先调用析构函数，然后调用 <strong>operator delete</strong> 函数释放内存（通常底层使用free实现）。</td>
<td>malloc/free是库函数，只能动态的申请和释放内存，无法强制要求其做自定义类型对象构造和析构工作。</td>
</tr>
<tr>
<td>重载</td>
<td>可重载。</td>
<td>malloc <strong>不允许重载</strong>。</td>
</tr>
<tr>
<td>内存区域</td>
<td>new 操作符从自由存储区（free store）上为对象动态分配内存空间。自由存储区是 C++ 基于new操作符的一个抽象概念，凡是通过new操作符进行内存申请，该内存即为自由存储区。</td>
<td>malloc 函数从堆上动态分配内存。而堆是操作系统中的术语，是操作系统所维护的一块特殊内存，用于程序的内存动态分配，C 语言使用 malloc 从堆上分配内存，使用 free 释放已分配的对应内存。</td>
</tr>
</tbody>
</table></div>
<p>从技术上来说，堆（heap）是C语言和操作系统的术语，堆是操作系统所维护的一块特殊内存，它提供了动态分配的功能，使用malloc()、free（）来申请/释放内存。</p>
<p>自由存储是C++中通过new和delete动态分配和释放对象的抽象概念。基本上，所有的C++编译器默认使用堆来实现自由存储。</p>
<p>也就是说，默认的全局运算符new和delete也许会使用malloc和free的方式申请和释放存储空间，也就是说自由存储区就位于堆上。</p>
<p>但程序员也可以通过重载操作符，改用其他内存来实现自由存储，例如<strong>全局变量做的对象池</strong>，这时自由存储区就不位于堆上了。</p>
<p><strong>堆是操作系统维护的一块内存，是一个物理概念，而自由存储是C++中通过new与delete动态分配和释放的对象的存储区，是一个逻辑概念。</strong></p>
<h3 id="c">C++内存管理</h3>
<h4 id="1_1">1. 堆、栈、常量区</h4>
<p>内存区分为5个区，分别是堆、栈、自由存储区、全局/静态存储区、常量存储区</p>
<h4 id="2_1">2. 内存泄露</h4>
<h4 id="3">3. 内存对齐</h4>
<h4 id="4-c">4. C++中一个类占用的内存字节</h4>
<ol>
<li>非静态成员变量总合。 </li>
<li>加上编译器为了CPU计算，作出的数据对齐处理。 </li>
<li>加上为了支持虚函数，产生的额外负担。</li>
</ol>
<h3 id="_2">面向对象</h3>
<h4 id="1_2">1. 面向对象的理解</h4>
<ol>
<li>抽象</li>
<li>封装</li>
<li>继承</li>
<li><strong>多态</strong></li>
</ol>
<h4 id="2_2">2. 重载和重写</h4>
<div class="pure-table-scrollable"><table class="pure-table pure-table-horizontal">
<thead>
<tr>
<th></th>
<th>作用域</th>
<th>描述</th>
<th>特点</th>
</tr>
</thead>
<tbody>
<tr>
<td>重载</td>
<td>相同</td>
<td>重载翻译自 overload，是指同一可访问区内被声明的<strong>几个具有不同参数列表（参数的类型，个数，顺序不同）的同名函数，根据参数列表确定调用哪个函数，重载不关心函数返回类型。</strong></td>
<td>1. 作用域相同<br/>2. 函数名相同<br/>3. 参数不同列表<br/>4. <u>virtual 关键字可有可无</u><br/>5. 返回类型可以不同</td>
</tr>
<tr>
<td>重写覆盖</td>
<td>不同</td>
<td>重写翻译自 override，是指<strong>派生类中</strong>存在重新定义的函数。其<strong>函数名，参数列表，返回值类型，所有都必须同基类中被重写的函数一致</strong>。只有函数体不同（花括号内），派生类调用时会调用派生类的重写函数，不会调用被重写函数。<strong>重写的基类中被重写的函数必须有 virtual 修饰</strong>。</td>
<td>1. 作用域不同（分别位于派生类与基类）<br/>2. 函数名，参数列表，返回值类型相同<br/>3. <u>基类函数必须有 virtual 关键字</u>，<u>不能有 static</u><br/>4. 重写函数的访问修饰符可以不同。尽管 virtual 是 private 的，派生类中重写改写为 public，protected 也是可以的</td>
</tr>
<tr>
<td>隐藏</td>
<td>不同</td>
<td><strong>指不同作用域中定义的同名函数构成隐藏（不要求函数返回值和函数参数类型相同）</strong>。比如<u>派生类成员函数隐藏与其同名的基类成员函数</u>、<u>类成员函数隐藏全局外部函数</u>。</td>
<td>1. 作用域不同<br />2. 函数名相同</td>
</tr>
</tbody>
</table></div>
<h4 id="3_1">3. 构造函数、深拷贝和浅拷贝</h4>
<p>默认的拷贝构造函数是浅拷贝，当对象内有指针成员函数的时候，<strong>浅拷贝只对指针进行拷贝</strong>，<strong>没有将指针指向的内存拷贝过来</strong>，需要程序员自己编写拷贝构造函数。</p>
<blockquote class="content-quote">
<p>https://blog.csdn.net/chen1234520nnn/article/details/83338990</p>
</blockquote>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">#include &lt;iostream&gt;  
using namespace std;

class Student
{
private:
    int num;
    char *name;   //此处类中包含指针
public:
    Student();
    ~Student();
};

Student::Student()
{
    name = new char(20);
    cout &lt;&lt; &quot;Student&quot; &lt;&lt; endl;

}
Student::~Student()
{
    cout &lt;&lt; &quot;~Student &quot; &lt;&lt; (int)name &lt;&lt; endl;
    delete name;
    name = NULL;
}

int main()
{
    {// 花括号让s1和s2变成局部对象，方便测试
        Student s1;
        Student s2(s1);// 复制对象
    }
    system(&quot;pause&quot;);
    return 0;
}
</code></span></code></pre>
<p>执行结果：调用一次构造函数，调用两次析构函数，两个对象的指针成员所指同一块内存，这会导致什么问题呢？name 指针被分配一次内存，但是程序结束时该内存却被释放了两次，会导致崩溃！</p>
<p>由于编译系统在我们没有自己定义拷贝构造函数时，会在拷贝对象时调用默认拷贝构造函数，进行的是浅拷贝！即对指针 name 拷贝后会出现两个指针指向同一个内存空间。</p>
<p>所以，<strong>在对含有指针成员的对象进行拷贝时，必须要自己定义拷贝构造函数，使拷贝后的对象指针成员有自己的内存空间，即进行深拷贝，这样就避免了内存泄漏发生</strong>。</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">//自己定义构造函数，进行深拷贝
Student::Student(const Student &amp;s)
{
    name = new char(20);
    memcpy(name, s.name, strlen(s.name));  
    cout &lt;&lt; &quot;copy Student&quot; &lt;&lt; endl;
}
</code></span></code></pre>
<p><strong>执行结果：</strong>调用一次构造函数，一次自定义拷贝构造函数，两次析构函数。两个对象的指针成员所指内存不同。<br />
<strong>总结：</strong>浅拷贝只是对指针的拷贝，<strong>拷贝后两个指针指向同一个内存空间</strong>，深拷贝不但对指针进行拷贝，而且对指针指向的内容进行拷贝，经<strong>深拷贝后的指针是指向两个不同地址的指针</strong>。</p>
<h4 id="4_1">4. 继承、多继承、菱形继承</h4>
<h4 id="5_1">5. 多态、虚函数</h4>
<blockquote class="content-quote">
<p>https://blog.csdn.net/caoshangpa/article/details/80112673</p>
</blockquote>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">class Base1                         class Base1     size(8):
{                                           +---
public:                              0      | base1_1
    int base1_1;                     4      | base1_2
    int base1_2;                            +---
    void foo(){}
};
--------------------------------------------------------------------------------------
class Base2                         class Base2     size(12):
{                                           +---
public:                              0      | {vfptr} &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 指向 虚函数指针数组 的指针
    int base2_1;                     4      | base2_1
    int base2_2;                     8      | base2_2
    virtual void base2_fun1() {}            +---
};                                  Base2::$vftable@:
                                            | &amp;Base2_meta
                                            |  0
                                     0      | &amp;Base2::base2_fun1
/* 类的大小由 成员变量 和 是否含有虚函数指针 决定。
（this 指针不占内存空间，this由编译器在编译的时候传入成员函数）*/
--------------------------------------------------------------------------------------
class Base3                         class Base3     size(12):
{                                           +---
public:                              0      | {vfptr} &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 指向 虚函数指针数组 的指针
    int base3_1;                     4      | base3_1
    int base3_2;                     8      | base3_2
    virtual void base3_fun1() {}            +---
    virtual void base3_fun2() {}    Base3::$vftable@:
};                                          | &amp;Base3_meta
                                            |  0
                                     0      | &amp;Base3::base3_fun1
                                     1      | &amp;Base3::base3_fun2
/* 虚函数指针是一个指向 [指针数组(数组元素指向虚函数)] 的指针。
 多个虚函数并不会增大类的大小 */
</code></span></code></pre>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">class Base1
{
public:
    int base1_1;
    int base1_2;
    virtual void base1_fun1() {}
    virtual void base1_fun2() {}
};

class Base2
{
public:
    int base2_1;
    int base2_2;
    virtual void base2_fun1() {}
    virtual void base2_fun2() {}
};

// 多继承
class Derive1 : public Base1, public Base2
{
public:
    int derive1_1;
    int derive1_2;
    virtual void base1_fun1() {}    // Base1 基类虚函数覆盖
    virtual void base2_fun2() {}    // Base2 基类虚函数覆盖
    virtual void derive1_fun1() {}  // 自身定义的虚函数
    virtual void derive1_fun2() {}  // 自身定义的虚函数
};

class Derive1   size(32):               &lt;&lt;&lt; Derive1::$vftable@Base1@:
        +---                            &lt;           | &amp;Derive1_meta
 0      | +--- (base class Base1)       &lt;           |  0
 0      | | {vfptr} &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;    0      | &amp;Derive1::base1_fun1 &lt;&lt; 重写 &lt;&lt;
 4      | | base1_1                          1      | &amp;Base1::base1_fun2
 8      | | base1_2                          2      | &amp;Derive1::derive1_fun1
        | +---                               3      | &amp;Derive1::derive1_fun2
12      | +--- (base class Base2)       
12      | | {vfptr} &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; Derive1::$vftable@Base2@:
16      | | base2_1                                 | -12
20      | | base2_2                          0      | &amp;Base2::base2_fun1
        | +---                               1      | &amp;Derive1::base2_fun2 &lt;&lt; 重写 &lt;&lt;
24      | derive1_1
28      | derive1_2
        +---
</code></span></code></pre>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">class Base1 { public: int base1_1; int base1_2; };

class Base2
{
public:
    int base2_1;
    int base2_2;
    virtual void base2_fun1() {}
    virtual void base2_fun2() {}
};

// 多继承
class Derive1 : public Base1, public Base2
{
public:
    int derive1_1;
    int derive1_2;
    virtual void derive1_fun1() {} // 自身定义的虚函数
    virtual void derive1_fun2() {} // 自身定义的虚函数
};

class Derive1   size(28):
        +---                            
 0      | +--- (base class Base2)           
 0      | | {vfptr} &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; Derive1::$vftable@:
 4      | | base2_1                                 | &amp;Derive1_meta
 8      | | base2_2                                 |  0
        | +---                               0      | &amp;Base2::base2_fun1
12      | +--- (base class Base1)            1      | &amp;Base2::base2_fun2
12      | | base1_1                          2      | &amp;Derive1::derive1_fun1
16      | | base1_2                          3      | &amp;Derive1::derive1_fun2
        | +---
20      | derive1_1
24      | derive1_2
        +---
/* 注意到，当只有一个基类含有虚函数时，整个虚函数表在最前面 */
</code></span></code></pre>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">class Base1 { public: int base1_1; int base1_2; };
class Base2 { public: int base2_1; int base2_2; };

// 多继承
class Derive1 : public Base1, public Base2
{
public:
    int derive1_1;
    int derive1_2;
    virtual void derive1_fun1() {} // 自身定义的虚函数
    virtual void derive1_fun2() {} // 自身定义的虚函数
};

class Derive1   size(28):
        +---
 0      | {vfptr} &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; Derive1::$vftable@:
 4      | +--- (base class Base1)                   | &amp;Derive1_meta
 4      | | base1_1                                 |  0
 8      | | base1_2                          0      | &amp;Derive1::derive1_fun1
        | +---                               1      | &amp;Derive1::derive1_fun2
12      | +--- (base class Base2)
12      | | base2_1
16      | | base2_2
        | +---
20      | derive1_1
24      | derive1_2
        +---
/* 注意到，当基类都不含有虚函数时，整个虚函数表依然在最前面 */
</code></span></code></pre>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">class Base1
{
public:
    int base1_1;
    int base1_2;
    virtual void base1_fun1() {}
    virtual void base1_fun2() {}
};

class Base2 { public: int base2_1; int base2_2; };

class Base3
{
public:
    int base3_1;
    int base3_2;
    virtual void base3_fun1() {}
    virtual void base3_fun2() {}
};

// 多继承
class Derive1 : public Base1, public Base2, public Base3
{
public:
    int derive1_1;
    int derive1_2;
    virtual void derive1_fun1() {}  // 自身定义的虚函数
    virtual void derive1_fun2() {}  // 自身定义的虚函数
};

class Derive1   size(40):                 &lt; Derive1::$vftable@Base1@:
        +---                              &lt;         | &amp;Derive1_meta
 0      | +--- (base class Base1)         &lt;         |  0
 0      | | {vfptr} &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;  0      | &amp;Base1::base1_fun1
 4      | | base1_1                          1      | &amp;Base1::base1_fun2
 8      | | base1_2                          2      | &amp;Derive1::derive1_fun1
        | +---                               3      | &amp;Derive1::derive1_fun2
12      | +--- (base class Base3) /* 有虚表的类在前面 */
12      | | {vfptr} &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; Derive1::$vftable@Base3@:
16      | | base3_1                                 | -12
20      | | base3_2                          0      | &amp;Base3::base3_fun1
        | +---                               1      | &amp;Base3::base3_fun2
24      | +--- (base class Base2) /* 无虚表的类在后面 */
24      | | base2_1
28      | | base2_2
        | +---
32      | derive1_1
36      | derive1_2
        +---
</code></span></code></pre>
<h5 id="c_1">C++ 多态的实现及原理</h5>
<p>C++的多态性用一句话概括就是：在基类的函数前加上 <strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>virtual</code></span></strong> 关键字，在派生类中重写该函数，运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类，就调用派生类的函数；如果对象类型是基类，就调用基类的函数。虚函数的实现是由两个部分组成的，虚函数指针与虚函数表。</p>
<p>1：用 <strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>virtual</code></span></strong> 关键字申明的函数叫做虚函数，虚函数肯定是类的成员函数。  </p>
<p>2：存在虚函数的类都有一个一维的虚函数表叫做虚表，类的对象有一个指向虚表开始的虚指针。虚表是和类对应的，虚表指针是和对象对应的。</p>
<p>3：多态性是一个接口多种实现，是面向对象的核心，分为类的多态性和函数的多态性。</p>
<p>4：多态用虚函数来实现，结合动态绑定。</p>
<p>5：纯虚函数是虚函数再加上 = 0</p>
<p>6：抽象类是指包括至少一个纯虚函数的类。</p>
<h5 id="_3">虚函数指针</h5>
<p>虚函数指针 <strong>(virtual function pointer)</strong> 从本质上来说就只是一个指向函数的指针，与普通的指针并无区别。它指向用户所定义的虚函数，具体是在子类里的实现，当子类调用虚函数的时候，实际上是通过调用该虚函数指针从而找到接口。</p>
<p>只有拥有 <strong>虚函数的类才会拥有虚函数指针</strong>，每一个虚函数也都会对应一个虚函数指针。所以拥有虚函数的类的所有对象都会因为虚函数产生额外的开销，并且也会在一定程度上降低程序速度。与JAVA不同，<strong>C++将是否使用虚函数这一权利交给了开发者，所以开发者应该谨慎的使用</strong>。</p>
<h5 id="_4">虚基类</h5>
<p>在继承方式前面加 <strong><span style="overflow-x: auto; max-width:100%; display:inline;"><code>virtual</code></span></strong>，当该基类通过多条派生路径被一个派生类继承时，该派生类只继承该基类一次，基类成员只保留一次。</p>
<ol>
<li>如果在虚基类中定义带有形参的构造函数，并且没有定义默认形似的构造函数，则在整个继承结构中，所有直接或间接的派生类都必须在构造函数的成员初始化列表中列对虚积累构造函数的调用，以初始化在基类中定义的数据成员。</li>
<li>建立一个对象时，如果这个对象中含有从虚基类继承来的成员，则虚基类的成员是由<strong>最远派生类</strong>的构造函数通过调用虚基类的构造函数进行初始化的。该派生类的其他基类堆许基类构造函数的调用都自动忽略。</li>
<li>若同一层次中同时包含虚基类和非虚基类，应先调用虚基类的构造函数，再调用非虚基类的构造函数，最后调用派生类的构造函数。</li>
<li><strong>对多个虚基类，构造函数的执行顺序时先左后右，自上而下</strong></li>
<li>对与非虚基类，构造函数的执行顺序时先左后右，自上而下</li>
<li>若虚基类由非虚基类派生而来，则先调用基类构造函数，再调用派生类的构造函数。</li>
</ol>
<h5 id="_5">纯虚函数与抽象类</h5>
<p>如果一个类至少含有一个纯虚函数，那就称这个类为抽象类</p>
<ol>
<li>抽象类只能用作其他类的基类，不能建立抽象类对象。</li>
<li>抽象类不能用做参数类型，函数返回类型和显示转换类型。但可以声明指向抽象类的指针变量，此指针变量可以指向他的派生类。</li>
<li>如果在抽象类的派生类中没有重新说明纯虚函数，则该函数在派生类中仍然为纯虚函数，而这个派生类仍然是抽象类。</li>
</ol>
<h4 id="6-this">6. this 指针</h4>
<blockquote class="content-quote">
<p>参考文献：</p>
<p>https://blog.csdn.net/alidada_blog/article/details/81290323</p>
<p>https://blog.csdn.net/starlee/article/details/2062586?utm<em>medium=distribute.pc</em>relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.control&amp;dist<em>request</em>id=&amp;depth<em>1-utm</em>source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.control</p>
</blockquote>
<h5 id="this">this指针的特征：</h5>
<ul>
<li><span style="overflow-x: auto; max-width:100%; display:inline;"><code>this</code></span> 指针的类型：类类型 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>*const.</code></span></li>
<li><span style="overflow-x: auto; max-width:100%; display:inline;"><code>this</code></span> 指针的地址寄存在 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>ecx</code></span> 中 （计数寄存器）.</li>
<li><span style="overflow-x: auto; max-width:100%; display:inline;"><code>this</code></span> 指针 <strong>并不是对象本身的一部分</strong>，不影响 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>sizeof</code></span> 的结果.</li>
<li><span style="overflow-x: auto; max-width:100%; display:inline;"><code>this</code></span> 的作用域在类“成员函数”的内部.</li>
<li><span style="overflow-x: auto; max-width:100%; display:inline;"><code>this</code></span> 指针是类“成员函数”的第一个默认隐含参数，编译器自动维护传递，类编写者不能显式传递.</li>
<li>只有在类的 <strong>非静态成员函数</strong> 中才可以使用this指针，其他任何函数都不允许.</li>
<li><span style="overflow-x: auto; max-width:100%; display:inline;"><code>this</code></span> 指针不可以 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>++ --</code></span> 操作 , 即 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>this</code></span> 指针的值不可以被改变.</li>
<li>参数个数确定的函数，<span style="overflow-x: auto; max-width:100%; display:inline;"><code>this</code></span> 指针是由 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>ecx</code></span> 传递的 , 在 <strong>变参函数</strong> 中最后一个传递的参数是 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>this</code></span> 指针.</li>
</ul>
<h5 id="__thiscall">__thiscall的调用特点：</h5>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">// thiscall_learn.cpp
#include &lt;iostream&gt;
using namespace std;

class Box
{
public:
    int volume(int height, int width, int length)
    {
        return height * width * length;
    }
};

int volume(int height, int width, int length)
{
    return height * width * length;
}

int main()
{
    Box t1, t2;
    t1.volume(2, 4, 5);
    t2.volume(3, 6, 9);
    volume(1, 2, 3);
    return 0;

}
</code></span></code></pre>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>g++ -S 
</code></span></code></pre>
<ul>
<li>参数的传递顺序：~~<strong>从右向左</strong>~~ （由编译器决定）</li>
<li>参数的传递方式：是利用栈传递.</li>
<li>堆栈平衡：调用者平衡堆栈(外平栈).</li>
<li><span style="overflow-x: auto; max-width:100%; display:inline;"><code>__thiscall</code></span> <strong>只能</strong> 够用在类的成员函数上.</li>
<li><strong>如果参数个数确定，<span style="overflow-x: auto; max-width:100%; display:inline;"><code>this</code></span> 指针通过 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>ecx</code></span> 传递给被调用者</strong>；<strong>如果参数不确定，<span style="overflow-x: auto; max-width:100%; display:inline;"><code>this</code></span> 指针在所有参数被压栈后压入栈堆.</strong></li>
<li>对参数个数不确定的，<strong>调用者清理堆栈</strong>，否则函数自己清理堆栈.</li>
</ul>
<h4 id="6-c">6. C++中内存泄漏的几种情况</h4>
<p>https://www.cnblogs.com/liushui-sky/p/7727865.html</p>
<h5 id="1-new-delete">1. 在类的构造函数和析构函数中没有匹配的调用 new 和 delete 函数</h5>
<h5 id="2_3">2. 没有正确地清除嵌套的对象指针</h5>
<h5 id="3-delete">3. 在释放对象数组时在delete中没有使用方括号</h5>
<h5 id="4_2">4. 指向对象的指针数组不等同于对象数组</h5>
<p>对象数组是指：数组中存放的是对象，只需要delete []p，即可调用对象数组中的每个对象的析构函数释放空间。</p>
<p>指向对象的指针数组是指：数组中存放的是指向对象的指针，不仅要释放每个对象的空间，还要释放每个指针的空间，delete []p只是释放了每个指针，但是并没有释放对象的空间，正确的做法，是通过一个循环，将每个对象释放了，然后再把指针释放了。（<strong>即动态二维数组时，不光要释放第二维存放指针数组的空间，也要释放指针数组中每个指针元素指向的空间</strong>）</p>
<h5 id="5_2">5. 缺少拷贝构造函数</h5>
<p>两次释放相同的内存是一种错误的做法，同时可能会造成堆的奔溃。</p>
<p>按值传递会调用（拷贝）构造函数，引用传递不会调用。</p>
<p><strong>即浅拷贝的时候，两个对象内部的指针指向同一个地址空间，第二个析构函数会释放第一个析构函数已经释放的地址空间，造成堆崩溃。</strong></p>
<h5 id="6">6. 缺少重载赋值运算符</h5>
<p>缺少 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>operator=()</code></span> 运算符的重载函数，造成与上述情况相同的结果。</p>
<h5 id="7-nonmodifying">7.  关于 nonmodifying 运算符重载的常见迷思</h5>
<p>a. 返回栈上对象的引用或者指针（也即返回局部对象的引用或者指针）。导致最后返回的是一个空引用或者空指针，因此变成野指针。</p>
<p>b. 返回内部静态对象的引用。</p>
<p>c. 返回一个泄露内存的动态分配的对象。导致内存泄露，并且无法回收。</p>
<h5 id="8">8. 没有将基类的析构函数定义为虚函数</h5>
<p>当基类指针指向子类对象时，如果基类的析构函数不是virtual，那么子类的析构函数将不会被调用，子类的资源没有正确是释放，因此造成内存泄露。</p>
<blockquote class="content-quote">
<p><strong>C++中，构造函数不可以是虚函数，而析构函数可以且常常是虚函数。</strong></p>
</blockquote>
<p><strong>野指针</strong>：指向被释放的或者访问受限内存的指针。</p>
<p>造成野指针的原因：</p>
<ol>
<li>指针变量没有被初始化（如果值不定，可以初始化为NULL）</li>
<li>指针被free或者delete后，没有置为NULL, free和delete只是把指针所指向的内存给释放掉，并没有把指针本身干掉，此时指针指向的是“垃圾”内存。释放后的指针应该被置为NULL.</li>
<li>指针操作超越了变量的作用范围，比如返回指向栈内存的指针就是野指针。</li>
</ol>
<h3 id="boost">Boost</h3>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>Boost</code></span> 是一个功能强大、构造精巧、跨平台、开源并且完全免费的 C++ 程序库。</p>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>Boost</code></span> 库的大多数组件不需要编译链接，我们在自己的源码里直接包含头文件即可。例如，如果要使用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>boost::tribool</code></span>，只需要在 C++ 源文件中添加如下 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>include</code></span> 语句：</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">#include &lt;boost/logic/tribool.hpp&gt;  //使用tribool库
</code></span></code></pre>
<h3 id="stl">STL</h3>
<h4 id="1-stl">1. STL基本组成部分</h4>
<h4 id="2-stl">2. STL常见容器</h4>
<h4 id="3-stl">3. STL常见容器的原理</h4>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>map</code></span> 和 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>set</code></span> 一样是关联式容器，它们的底层容器都是红黑树，区别就在于 map 的值不作为键，键和值是分开的。</p>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>map</code></span> 或 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>set</code></span> 中的关键字必须是唯一的。</p>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>multimap</code></span> 和 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>multiset</code></span> 没有此限制，他们允许多个元素具有相同的关键字。</p>
<h3 id="c_2">c++</h3>
<h4 id="1_3">1.智能指针</h4>
<blockquote class="content-quote">
<p><a href="https://www.cnblogs.com/lanxuezaipiao/p/4132096.html">C++智能指针简单剖析</a></p>
<p><a href="https://blog.csdn.net/albertsh/article/details/81561822?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160284832919195264739610%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;request_id=160284832919195264739610&amp;biz_id=0&amp;utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v1-4-81561822.pc_v1_rank_blog_v1&amp;utm_term=智能指针&amp;spm=1018.2118.3001.4187">智能指针：auto_ptr浅析</a> (已经被C++11弃用)</p>
<p><a href="https://blog.csdn.net/albertsh/article/details/82701573?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160284832919195264739610%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;request_id=160284832919195264739610&amp;biz_id=0&amp;utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v1-5-82701573.pc_v1_rank_blog_v1&amp;utm_term=智能指针&amp;spm=1018.2118.3001.4187">智能指针：unique_ptr浅析</a></p>
<p><a href="https://blog.csdn.net/albertsh/article/details/81807927?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160284832919195264739610%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&amp;request_id=160284832919195264739610&amp;biz_id=0&amp;utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v1-3-81807927.pc_v1_rank_blog_v1&amp;utm_term=智能指针&amp;spm=1018.2118.3001.4187">智能指针：shared_ptr浅析</a></p>
<p><a href="https://blog.csdn.net/qq_34992845/article/details/69218843">浅谈shared<em>ptr及shared</em>ptr涉及到的循环引用问题</a></p>
<p><a href="https://blog.csdn.net/albertsh/article/details/82286999">智能指针：weak_ptr浅析</a></p>
</blockquote>
<h4 id="auto_ptr">auto_ptr</h4>
<p>（C++98的方案，C++11已经抛弃）采用所有权模式。</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">auto_ptr&lt;string&gt; p1 (new string (&quot;I reigned lonely as a cloud.&quot;)); 
auto_ptr&lt;string&gt; p2; 
p2 = p1; //auto_ptr不会报错.
cout &lt;&lt; *p1; //报错！！
</code></span></code></pre>
<p>此时不会报错，p2剥夺了p1的所有权，在这段程序执行之后，当程序运行时访问p1将会报错。所以 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>auto_ptr</code></span> 的缺点是：存在潜在的内存崩溃问题！</p>
<h4 id="uniqueptrautoptr">unique<em>ptr（替换auto</em>ptr）</h4>
<p>采用所有权模式，还是上面那个例子。</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">unique_ptr&lt;string&gt; p3 (new string (&quot;auto&quot;)); //#4
unique_ptr&lt;string&gt; p4；                      //#5
p4 = p3; //报错！！
</code></span></code></pre>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>unique_ptr</code></span> 还有更聪明的地方，当程序试图将一个 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>unique_ptr</code></span> 赋值给另一个时：</p>
<ol>
<li>如果源 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>unique_ptr</code></span> 是个临时右值，编译器允许这么做；</li>
<li>如果源 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>unique_ptr</code></span> 将存在一段时间，编译器将禁止这么做；</li>
</ol>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">unique_ptr&lt;string&gt; pu1(new string (&quot;hello world&quot;)); 
unique_ptr&lt;string&gt; pu2; 
pu2 = pu1; // #1 不允许

unique_ptr&lt;string&gt; pu3; 
pu3 = unique_ptr&lt;string&gt;(new string (&quot;You&quot;));   // #2 允许
</code></span></code></pre>
<h4 id="shared_ptr">shared_ptr</h4>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>shared_ptr</code></span> 是为了解决 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>auto_ptr</code></span> 在对象所有权上的局限性 ( <span style="overflow-x: auto; max-width:100%; display:inline;"><code>auto_ptr</code></span> 是独占的)，在使用引用计数的机制上提供了可以共享所有权的智能指针。</p>
<div class="pure-table-scrollable"><table class="pure-table pure-table-horizontal">
<thead>
<tr>
<th>成员函数</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td><span style="overflow-x: auto; max-width:100%; display:inline;"><code>use_count</code></span></td>
<td>返回引用计数的个数</td>
</tr>
<tr>
<td><span style="overflow-x: auto; max-width:100%; display:inline;"><code>unique</code></span></td>
<td>返回是否是独占所有权( <span style="overflow-x: auto; max-width:100%; display:inline;"><code>use_count</code></span> 为 1 )</td>
</tr>
<tr>
<td><span style="overflow-x: auto; max-width:100%; display:inline;"><code>swap</code></span></td>
<td>交换两个 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>shared_ptr</code></span> 对象(即交换所拥有的对象)</td>
</tr>
<tr>
<td><span style="overflow-x: auto; max-width:100%; display:inline;"><code>reset</code></span></td>
<td>放弃内部对象的所有权或拥有对象的变更，会引起原有对象的引用计数的减少</td>
</tr>
<tr>
<td><span style="overflow-x: auto; max-width:100%; display:inline;"><code>get</code></span></td>
<td>返回内部对象(指针)，由于已经重载了()方法, 因此和直接使用对象是一样的</td>
</tr>
</tbody>
</table></div>
<h4 id="weak_ptr">weak_ptr</h4>
<p>当两个对象相互使用一个 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>shared_ptr</code></span> 成员变量指向对方，会造成循环引用，使引用计数失效，从而导致内存泄漏。</p>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>weak_ptr</code></span> 是一种不控制对象生命周期的智能指针，<strong>它指向一个 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>shared_ptr</code></span> 管理的对象</strong>。</p>
<p>（<strong>由于对象可能不存在，我们不能使用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>weak_ptr</code></span> 直接访问对象，而必须调用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>lock</code></span>，此函数检查<span style="overflow-x: auto; max-width:100%; display:inline;"><code>weak_ptr</code></span> 指向的对象是否存在。如果存在，<span style="overflow-x: auto; max-width:100%; display:inline;"><code>lock</code></span> 返回一个指向共享对象的 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>shared_ptr</code></span>,如果不存在，<span style="overflow-x: auto; max-width:100%; display:inline;"><code>lock</code></span> 将返回一个空指针</strong>）。</p>
<h4 id="weak_ptr_1">测试 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>weak_ptr</code></span> 常用函数的用法</h4>
<ol>
<li>
<p>使用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>expired</code></span> 函数来检测指针是否过期</p>
</li>
<li>
<p>使用 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>lock</code></span> 函数来获取其对应的 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>shared_ptr</code></span> 对象</p>
</li>
</ol>
<h3 id="_6">对全部三种智能指针都应避免的一点：</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">string vacation(&quot;I wandered lonely as a cloud.&quot;);
shared_ptr&lt;string&gt; pvac(&amp;vacation); // 错误，pvac过期时，程序将把delete运算符用于非堆内存，这是错误的
</code></span></code></pre>
<h4 id="2-c11">2. 右值引用（C++11）</h4>
<blockquote class="content-quote">
<p><a href="/public/download/[c++11]我理解的右值引用、移动语义和完美转发">[c++11]我理解的右值引用、移动语义和完美转发</a></p>
</blockquote>
<h5 id="_7">左值、右值</h5>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>C++</code></span>中所有的值都必然属于左值、右值二者之一。</p>
<div class="pure-table-scrollable"><table class="pure-table pure-table-horizontal">
<thead>
<tr>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>左值</td>
<td>指表达式结束后依然存在的 <strong>持久化对象</strong></td>
<td>所有的具名变量或者对象都是左值</td>
</tr>
<tr>
<td>右值</td>
<td>指表达式结束时就不再存在的 <strong>临时对象</strong></td>
<td>右值不具名</td>
</tr>
</tbody>
</table></div>
<p>很难得到左值和右值的真正定义，但是有一个可以区分左值和右值的便捷方法：<strong>看能不能对表达式取地址，如果能，则为左值，否则为右值</strong>。</p>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>c++98</code></span>中的引用很常见了，就是给变量取了个别名，在<span style="overflow-x: auto; max-width:100%; display:inline;"><code>c++11</code></span>中，因为增加了<strong>右值引用(rvalue reference)</strong>的概念，所以<span style="overflow-x: auto; max-width:100%; display:inline;"><code>c++98</code></span>中的引用都称为了<strong>左值引用(lvalue reference)</strong>。</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">int a = 10; 
int &amp;refA = a; // refA是a的别名， 修改refA就是修改a, a是左值，左移是左值引用

int &amp;b = 1; //// 编译错误! //// 1是右值，不能够使用左值引用
</code></span></code></pre>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>c++11</code></span>中的右值引用使用的符号是<span style="overflow-x: auto; max-width:100%; display:inline;"><code>&amp;&amp;</code></span>，如</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">int &amp;&amp;a = 1; // 实质上就是将不具名(匿名)变量取了个别名
int b = 1;
int &amp;&amp;c = b; //// 编译错误！//// 不能将一个左值复制给一个右值引用

class A {
  public:
    int a;
};

A getTemp() {
    return A();
}

A &amp;&amp;a = getTemp();  // getTemp()的返回值是右值（临时变量）
</code></span></code></pre>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>getTemp()</code></span>返回的右值本来在表达式语句结束后，其生命也就该终结了（因为是临时变量），而通过右值引用，该右值又重获新生，其 <strong>生命期将与右值引用类型变量<span style="overflow-x: auto; max-width:100%; display:inline;"><code>a</code></span>的生命期一样</strong>，只要<span style="overflow-x: auto; max-width:100%; display:inline;"><code>a</code></span>还活着，该右值临时变量将会一直存活下去。实际上就是给那个临时变量取了个名字。</p>
<h4 id="3_2">3. 类型转换</h4>
<h5 id="static_cast">static_cast</h5>
<p>用来进行比较“自然”和低风险的转换，比如整形和实数型、字符型之间互相转换。<br />
不能在不同类型类型的指针之间互相转换，也不能用于整型和指针之间的互相转换，也不能用于不同类型的引用之间的转换。</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">#include &lt;iostream&gt;
using namespace std;
class A
{
public:
    operator int() { return 1; }
    operator char*() { return NULL; }
};
int main()
{
    A a;
    int n;
    char* p = &quot;New Dragon Inn&quot;;
    n = static_cast &lt;int&gt; (3.14);   // n 的值变为 3
    n = static_cast &lt;int&gt; (a);      // 调用 a.operator int，n 的值变为 1
    p = static_cast &lt;char*&gt; (a);    // 调用 a.operator char*，p 的值变为 NULL
    n = static_cast &lt;int&gt; (p);      // 编译错误，static_cast不能将指针转换成整型
    p = static_cast &lt;char*&gt; (n);    // 编译错误，static_cast 不能将整型转换成指针
    return 0;
}
</code></span></code></pre>
<h5 id="reinterpret_cast">reinterpret_cast</h5>
<p>用来进行各种不同类型的指针之间的转换、不同类型的引用之间转换、以及指针和能容纳得下指针的整数类型之间的转换。转换的时候，执行的是逐个比特拷贝的操作。</p>
<h5 id="const_cast">const_cast</h5>
<p>用来进行去除const属性的转换。将const引用转换成同类型的非const引用，将const指针转换为同类型的非const指针时用它。</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-c++">const int a = 7;
const int* p = &amp;a;
int* q = const_cast&lt;int*&gt;(p);
*q = 20;
</code></span></code></pre>
<h5 id="dynamic_cast">dynamic_cast</h5>
<p>专门用于将多态基类的指针或引用，强制转换为派生类的指针或引用，而且能够检查转换的安全性。对于不安全的指针转换，转换结果返回NULL。不能用于将非多态基类的指针或引用，强制转换为派生类的指针或引用。</p>
<h4 id="4-lambda">4. Lambda</h4>
<h3 id="_8">操作系统基础</h3>
<h4 id="1-linux">1. Linux常见命令</h4>
<h4 id="2_4">2. 文件权限</h4>
<h4 id="3_3">3. 软链接和硬链接</h4>
<h5 id="_9">符号链接（软链接）</h5>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">ln -s old.file soft.link
ln -s old.dir soft.link.dir
</code></span></code></pre>
<p>软链接（也叫符号链接）与硬链接不同，文件用户数据块中存放的内容是另一文件的路径名的指向。软链接就是一个普通文件，只是数据块内容有点特殊。软链接可对文件或目录创建。</p>
<p>软链接主要应用于以下两个方面：一是方便管理，例如可以把一个复杂路径下的文件链接到一个简单路径下方便用户访问；另一方面就是解决文件系统磁盘空间不足的情况。例如某个文件文件系统空间已经用完了，但是现在必须在该文件系统下创建一个新的目录并存储大量的文件，那么可以把另一个剩余空间较多的文件系统中的目录链接到该文件系统中，这样就可以很好的解决空间不足问题。<strong>删除软链接并不影响被指向的文件</strong>，但<strong>若被指向的原文件被删除，则相关软连接就变成了死链接</strong>。</p>
<h5 id="_10">硬链接</h5>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">link oldfile newfile 
ln oldfile newfile
</code></span></code></pre>
<p>硬链接是通过索引节点进行的链接。在Linux中，多个文件指向同一个索引节点是允许的，像这样的链接就是硬链接。硬链接只能在同一文件系统中的文件之间进行链接，<strong>不能对目录进行创建</strong>。如果删除硬链接对应的源文件，则硬链接文件仍然存在，而且保存了原有的内容，这样可以起到防止因为误操作而错误删除文件的作用。由于硬链接是有着相同 inode 号仅文件名不同的文件，因此，删除一个硬链接文件并不影响其他有相同 inode 号的文件。</p>
<div class="pure-table-scrollable"><table class="pure-table pure-table-horizontal">
<thead>
<tr>
<th></th>
<th>软链接（符号链接）</th>
<th>硬链接</th>
</tr>
</thead>
<tbody>
<tr>
<td>共享方式</td>
<td>利用符号链实现文件共享</td>
<td>基于索引结点的共享方式</td>
</tr>
<tr>
<td>链接文件</td>
<td>引用计数直接复制</td>
<td>引用计数加1</td>
</tr>
<tr>
<td>删除文件</td>
<td>不对软链接操作</td>
<td>引用计数减1 引用计数=0：删除文件 引用计数&gt;0：保留文件</td>
</tr>
<tr>
<td>优点</td>
<td></td>
<td>查找速度更快</td>
</tr>
</tbody>
</table></div>
<h4 id="4_3">4. 静态库和动态库</h4>
<blockquote class="content-quote">
<p>https://blog.csdn.net/dd_hello/article/details/81782934</p>
</blockquote>
<p>库有两种：静态库（.a、.lib）和动态库（.so、.dll）。</p>
<h5 id="_11">静态库</h5>
<p>之所以成为【静态库】，是因为在链接阶段，会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。</p>
<p>试想一下，静态库与汇编生成的目标文件一起链接为可执行文件，那么静态库必定跟.o文件格式相似。其实一个静态库可以简单看成是<strong>一组目标文件（ .o/.obj 文件）的集合</strong>，即很多目标文件经过压缩打包后形成的一个文件。静态库特点总结：</p>
<ul>
<li>静态库对函数库的链接是放在<strong>编译时期</strong>完成的。</li>
<li>程序在运行时与函数库再无瓜葛，移植方便。</li>
<li>浪费空间和资源，因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。</li>
</ul>
<h6 id="linux">Linux</h6>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>g++ -c StaticMath.cpp
ar -crv libstaticmath.a StaticMath.o
</code></span></code></pre>
<p>Linux下使用静态库，只需要在编译的时候，指定静态库的搜索路径（-L选项）、指定静态库名（不需要lib前缀和.a后缀，-l选项）。</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>g++ TestStaticLibrary.cpp -L../StaticLibrary -lstaticmath
</code></span></code></pre>
<ul>
<li><span style="overflow-x: auto; max-width:100%; display:inline;"><code>-L</code></span>：表示要连接的库所在目录</li>
<li><span style="overflow-x: auto; max-width:100%; display:inline;"><code>-l</code></span>：指定链接时需要的动态库，编译器查找动态连接库时有隐含的命名规则，即在给出的名字前面加上lib，后面加上.a或.so来确定库的名称。</li>
</ul>
<h5 id="_12">动态库</h5>
<p>为什么需要动态库，其实也是静态库的特点导致。</p>
<ul>
<li>空间浪费是静态库的一个问题。</li>
<li>另一个问题是静态库对程序的更新、部署和发布页会带来麻烦。如果静态库liba.lib更新了，所以使用它的应用程序都需要重新编译、发布给用户（对于玩家来说，可能是一个很小的改动，却导致整个程序重新下载，<strong>全量更新</strong>）。</li>
<li>动态库在程序编译时并不会被连接到目标代码中，而是在程序运行是才被载入。<strong>不同的应用程序如果调用相同的库，那么在内存里只需要有一份该共享库的实例</strong>，规避了空间浪费问题。动态库在程序运行是才被载入，也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可，<strong>增量更新</strong>。</li>
</ul>
<p>动态库特点总结：</p>
<ul>
<li>
<p>动态库把对一些库函数的链接载入推迟到程序运行的时期。</p>
</li>
<li>
<p>可以实现进程之间的资源共享。（因此动态库也称为共享库）</p>
</li>
<li>
<p>将一些程序升级变得简单。</p>
</li>
<li>
<p>甚至可以真正做到链接载入完全由程序员在程序代码中控制（<strong>显示调用</strong>）。</p>
</li>
</ul>
<p>Window与Linux执行文件格式不同，在创建动态库的时候有一些差异。</p>
<ul>
<li>在Windows系统下的执行文件格式是PE格式，动态库需要一个<strong>DllMain函数做出初始化的入口，通常在导出函数的声明时需要有_declspec(dllexport)</strong>关键字。</li>
<li>Linux下gcc编译的执行文件默认是ELF格式，<strong>不需要初始化入口，亦不需要函数做特别的声明，</strong>编写比较方便。</li>
</ul>
<p>与创建静态库不同的是，不需要打包工具（ar、lib.exe），直接使用编译器即可创建动态库。</p>
<h6 id="linux_1">linux动态库的命名规则</h6>
<p>动态链接库的名字形式为 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>libxxx.so</code></span>，前缀是 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>lib</code></span>，后缀名为 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>“.so”</code></span>。</p>
<p>首先，生成目标文件，此时要加编译器选项 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>-fpic</code></span></p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>g++ -fPIC -c DynamicMath.cpp
</code></span></code></pre>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>-fPIC</code></span> 创建与地址无关的编译程序（pic，position independent code），是为了能够在多个应用程序间共享。</p>
<p>然后，生成动态库，此时要加链接器选项 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>-shared</code></span></p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">g++ -shared -o libdynmath.so DynamicMath.o
</code></span></code></pre>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>-shared</code></span> 指定生成动态链接库。</p>
<p>其实上面两个步骤可以 <strong>合并为一个命令</strong>：</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code>g++ -fPIC -shared -o libdynmath.so DynamicMath.cpp
</code></span></code></pre>
<h4 id="5_3">5. 虚拟地址空间</h4>
<h3 id="linux_2">Linux开发基础</h3>
<h4 id="1-makefile">1. Makefile</h4>
<p>介绍一下Make？为什么使用make？</p>
<p>1、包含多个源文件的项目在编译时有长而复杂的命令行，可以通过 makefile 保存这些命令行来简化该工作 。<br />
2、make 可以减少重新编译所需要的时间，因为 make 可以识别出哪些文件是新修改的 。<br />
3、Make 维护了当前项目中各文件的相关关系，从而可以在编译前检查是否可以找到所有的文件。 </p>
<h4 id="2-gdb">2. GDB调试</h4>
<h4 id="3-api">3. 基本的API</h4>
<h3 id="linux_3">Linux多线程</h3>
<h5 id="_13">进程和线程的区别</h5>
<p>进程是资源分配的最小单位，线程是CPU调度的最小单位。</p>
<p>计算机在执行程序时，会为程序创建相应的进程，进行资源分配时，是以进程为单位进行相应的分配。</p>
<p>每个进程都有相应的线程，在执行程序时，实际上是执行相应的一系列线程。</p>
<h4 id="1_4">1. 井程状态、并行和并发</h4>
<h4 id="2_5">2. 瓜儿进程、僵尸进程</h4>
<h4 id="3_4">3. 进程间通信的几种方式</h4>
<ol>
<li><strong>共享存储 SharedMemory</strong>：共享内存就是映射一段能被其他进程所访问的内存，这段共享内存由一个进程创建，但多个进程都可以访问。共享内存是最快的 IPC 方式，它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制，如信号量，配合使用，来实现进程间的同步和通信。</li>
<li><strong>管道</strong>：管道是一种半双工的通信方式，数据只能单向流动，而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。<ol>
<li>普通管道 PIPE, 通常有两种限制，一是半双工,数据同时只能单向传输;二是只能在父子或者兄弟进程间使用。</li>
<li>命令流管道 s_pipe: 去除了第一种限制，<strong>为全双工</strong>，可以同时双向传输。</li>
<li>命名管道 FIFO，去除了第二种限制，可以在许多并不相关的进程之间进行通讯。</li>
</ol>
</li>
<li><strong>消息队列 MessageQueue</strong>：消息队列是由消息的链表，存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。</li>
<li><strong>信号量 Semaphore</strong>：信号量是一个计数器，可以用来控制多个进程对共享资源的访问。它常作为一种锁机制，防止某进程正在访问共享资源时，其他进程也访问该资源。因此，主要作为进程间以及同一进程内不同线程之间的同步手段。</li>
<li><strong>套接字 Socket</strong>：套解口也是一种进程间通信机制，与其他通信机制不同的是，它可用于不同及其间的进程通信。</li>
</ol>
<h4 id="4_4">4. 有名管道、匿名管道</h4>
<h4 id="5_4">5. 内存映射、 定时器、信号、守护进程</h4>
<p><strong>同源策略是浏览器的安全基石，但互联网业务往往需要实现跨域通信，以下哪一种方案可以实现跨域？（  ）</strong></p>
<p>同源策略（Same Origin Policy，SOP）是指浏览器请求的资源必须是同域名、同协议、同端口。不同源的客户端脚本（js，actionscript）在没有明确的授权的情况下不能读取对方的资源。</p>
<p>跨源资源（CrossOrigin Resources Sharing，CORS ）是一种允许多种资源在一个 web 页面请求域之外的另一个域的资源的协议，是为了让 AJAX 能够跨域而生的。</p>
<p>内容安全策略（Content Security Policy，CSP）是一种白名单机制，限制网站中是否可以包含某来源的内容。<br />
Oauth 是一个关于授权的开放网络标准，相当于在客户端与服务器之间添加了一个授权层。</p>
<h3 id="linux_4">Linux网络编程</h3>
<h4 id="1-macip">1. MAC地址、IP地址、 端口、协议</h4>
<h4 id="2_6">2. 网络参考模型</h4>
<h4 id="3_5">3. 字节序、字节序转换函数</h4>
<h4 id="4-ip">4. IP地址转换函数</h4>
<h4 id="5-socket">5. socket地址</h4>
<h3 id="tcp">TCP协议</h3>
<h4 id="1-tcp">1. TCP协议头</h4>
<h4 id="2_7">2. 三次握手</h4>
<h4 id="3_6">3. 四次挥手</h4>
<h4 id="4_5">4. 滑动窗口</h4>
<h4 id="5-tcp">5. TCP状态转换</h4>
<h4 id="6_1">6. 半关闭、端口复用</h4>
<h3 id="_14">多路复用</h3>
<h4 id="1-i0">1. 几种I0模型</h4>
<p>阻塞IO、非阻塞IO、多路复用IO、信号驱动IO以及异步IO.</p>
<h5 id="1io">（1）阻塞IO</h5>
<p>最传统的一种IO模型，即在读写数据过程中会发生阻塞现象。</p>
<p>当用户线程发出IO请求之后，内核会去查看数据是否就绪，如果没有就绪就会等待数据就绪，而用户线程就会处于阻塞状态，用户线程交出CPU。当数据就绪之后，内核会将数据拷贝到用户线程，并返回结果给用户线程，用户线程才解除block状态。</p>
<h5 id="2io">（2）非阻塞IO模型</h5>
<p>当用户线程发起一个read操作后，并不需要等待，而是马上就得到了一个结果。如果结果是一个error时，它就知道数据还没有准备好，于是它可以再次发送read操作。一旦内核中的数据准备好了，并且又再次收到了用户线程的请求，那么它马上就将数据拷贝到了用户线程，然后返回。</p>
<p>所以事实上，在非阻塞IO模型中，用户线程需要不断地询问内核数据是否就绪，也就说<strong>非阻塞IO不会交出CPU</strong>，而会<strong>一直占用CPU</strong>。</p>
<h5 id="3io">（3）多路复用IO模型</h5>
<p>多路复用IO模型是目前使用得比较多的模型。</p>
<p>在多路复用IO模型中，会有一个线程不断去轮询多个socket的状态，只有当socket真正有读写事件时，才真正调用实际的IO读写操作。因为在多路复用IO模型中，只需要使用一个线程就可以管理多个socket，系统不需要建立新的进程或者线程，也不必维护这些线程和进程，并且只有在真正有socket读写事件进行时，才会使用IO资源，所以它大大减少了资源占用。</p>
<h5 id="4io">（4）信号驱动IO模型</h5>
<p>在信号驱动IO模型中，当用户线程发起一个IO请求操作，会给对应的socket注册一个信号函数，然后用户线程会继续执行，当内核数据就绪时会发送一个信号给用户线程，用户线程接收到信号之后，便在信号函数中调用IO读写操作来进行实际的IO请求操作。这个一般用于UDP中，对TCP套接口几乎是没用的，原因是该信号产生得过于频繁，并且该信号的出现并没有告诉我们发生了什么事情。</p>
<h5 id="5io">（5）异步IO模型</h5>
<p>异步IO模型才是最理想的IO模型，在异步IO模型中，当用户线程发起read操作之后，立刻就可以开始去做其它的事。而另一方面，从内核的角度，当它受到一个asynchronous read之后，它会立刻返回，说明read请求已经成功发起了，因此不会对用户线程产生任何block。然后，内核会等待数据准备完成，然后将数据拷贝到用户线程，当这一切都完成之后，内核会给用户线程发送一个信号，告诉它read操作完成了。也就说用户线程完全不需要关心实际的整个IO操作是如何进行的，只需要先发起一个请求，当接收内核返回的成功信号时表示IO操作已经完成，可以直接去使用数据了。</p>
<h4 id="2-select">2. select</h4>
<p>select是一个计算机函数，位于头文件#include <sys/select.h> 。该函数用于监视 <strong>文件描述符</strong> 的变化情况——读写或是异常。</p>
<blockquote class="content-quote">
<p>文件描述符：<a href="https://baike.baidu.com/item/内核/108410">内核</a>（kernel）利用文件描述符（file descriptor）来访问文件。文件描述符是<a href="https://baike.baidu.com/item/非负整数/2951833">非负整数</a>。打开现存文件或新建文件时，内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。</p>
</blockquote>
<h4 id="3-poll">3. poll</h4>
<p>poll 是 Linux 中的字符设备驱动中的一个函数。Linux 2.5.44版本后，poll 被 epoll 取代。和 select 实现的功能差不多，poll 的作用是把当前的文件指针挂到等待队列。</p>
<h4 id="4-epoll">4. epoll</h4>
<p>epoll 是 Linux 内核为处理 <strong>大批量文件描述符</strong> 而作了改进的 poll，是 Linux 下多路复用 IO 接口 select/poll 的增强版本，它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候，它无须遍历整个被侦听的描述符集，只要遍历那些被内核IO事件异步唤醒而加入 Ready 队列的描述符集合就行了。epoll 除了提供 select/poll 那种IO事件的 <strong>水平触发</strong>（Level Triggered）外，还提供了 <strong>边缘触发</strong>（Edge Triggered），这就使得用户空间程序有可能缓存IO状态，减少 epoll<em>wait/epoll</em>pwait 的调用，提高应用程序效率。</p>
<h4 id="5-reactor-proactor">5. Reactor 和 Proactor 模式</h4>
<h3 id="_15">数据库</h3>
<h4 id="1-mysql">1. MySQL索引</h4>
<h5 id="mysqlb">为什么mysql索引用B+树而不用哈希表？</h5>
<p>Hash 索引仅仅能满足”=”,”IN”和”&lt;=&gt;”查询，不能使用范围查询。</p>
<p>Hash 索引无法被用来避免数据的排序操作。</p>
<p>Hash 索引不能利用部分索引键查询。</p>
<p>Hash 索引在任何时候都不能避免表扫描。</p>
<p>Hash 索引遇到大量Hash值相等的情况后性能并不一定就会比B+Tree索引高。</p>
<h4 id="2-mysql">2. MySQL事务</h4>
<h4 id="3_7">3. 数据库的锁</h4>
<h3 id="_16">设计模式</h3>
<h4 id="1_5">1. 单例设计模式</h4>
<p>https://blog.csdn.net/konglongdanfo1/article/details/83381403</p>
<h4 id="2_8">2. 懒汉式和饿汉式</h4>
<h4 id="3_8">3. 厂设计模式</h4>
<h4 id="4_6">4. 装饰设计模式</h4>
<h4 id="5_5">5. 观察者设计模式</h4>
<p>递归、贪心、模拟、数学、双指针、二分、位运算、哈希、字符串、排序、分治、动态规划、搜<br />
索、回溯、dfs、 bfs、 并查集、数组、链表、栈、队列、堆、树</p>
<h3 id="_17">垃圾回收</h3>
<blockquote class="content-quote">
<p>https://blog.csdn.net/u012611878/article/details/78947267</p>
</blockquote>
<h4 id="_18">有向可达图与根集</h4>
<p><img class="pure-img" alt="这里写图片描述" src="https://zromyk.gitee.io/myblog-figurebed/post/C++岗位面试知识.assets/SouthEast-20210328114501130.png" /></p>
<h4 id="1_6">1. 引用计数算法</h4>
<p>缺点一</p>
<p>循环引用</p>
<p>缺点二</p>
<p>是多个线程同时对引用计数进行增减时，引用计数的值可能会产生不一致的问题，必须使用并发控制机制解决这一问题，也是一个不小的开销。</p>
<h4 id="2-mark-sweep">2. Mark &amp; Sweep （标记清除算法）</h4>
<p>这个算法也称为标记清除算法，为McCarthy独创。它也是目前公认的最有效的GC方案。</p>
<p>Mark&amp;Sweep垃圾收集器由标记阶段和回收阶段组成，标记阶段标记出根节点所有可达的对节点，清除阶段释放每个未被标记的已分配块。典型地，块头部中空闲的低位中的一位用来表示这个块是否已经被标记了。</p>
<h4 id="3_9">3. 节点复制算法</h4>
<p><img class="pure-img" alt="这里写图片描述" src="https://zromyk.gitee.io/myblog-figurebed/post/C++岗位面试知识.assets/SouthEast.png" /></p>
<p>而节点复制算法则刚好相反，当需要回收的对象越多时，它的开销很小，而当大部分对象都不需要回收时，其开销反而很大。 </p>
<h4 id="4_7">4. 分代回收</h4>
<p>而高级GC技术中最重要的一种为分代回收。它的基本思路是这样的：程序中存在大量的这样的对象，它们被分配出来之后很快就会被释放，但如果一个对象分配后相当长的一段时间内都没有被回收，那么极有可能它的生命周期很长，尝试收集它是无用功。为了让GC变得更高效，我们应该对刚诞生不久的对象进行重点扫描，这样就可以回收大部分的垃圾。为了达到这个目的，我们需要依据对象的”年龄“进行分代，刚刚生成不久的对象划分为新生代，而存在时间长的对象划分为老生代，根据实现方式的不同，可以划分为多个代。</p>
<p>首先从根开始进行一次常规扫描，扫描过程中如果遇到老生代对象则不进行递归扫描，这样可大大减少扫描次数。这个过程可使用标记清除算法或者复制收集算法。然后，把扫描后残留下来的对象划分到老生代，若是采用标记清除算法，则应该在对象上设置某个标志位标志其年龄；若是采用复制收集，则只需要把新的存储区域内对象设置为老生代就可以了。而实际的实现上，分代回收算法的方案五花八门，常常会融合几种基本算法。</p>
<h3 id="_19">计算机网络</h3>
<h4 id="1tcpip">1、TCP/IP五层模型？</h4>
<p><a href="https://blog.csdn.net/ffsiwei/article/details/82121010">TCP/IP五层模型</a></p>
<ol>
<li><strong>物理层</strong>：负责光电信号传递方式。集线器工作在物理层。以太网协议。 </li>
<li><strong>数据链路层</strong>：负责设备之间的数据帧的传输和识别。交换机工作在数据链路层。例如网卡设备的驱动，帧同步，冲突检测，数据差错校验等工作。 </li>
<li><strong>网络层</strong>：负责地址管理和路由选择。路由器工作在网络层。 </li>
<li><strong>传输层</strong>：负责两台主机之间的数据传输。 </li>
<li><strong>应用层</strong>：负责应用程序之间的沟通。网络编程主要针对的就是应用层。</li>
</ol>
<h4 id="2tcp">2、TCP怎么保证可靠传输？</h4>
<p><a href="https://www.jianshu.com/p/6aac4b2a9fd7">TCP 协议如何保证可靠传输</a></p>
<ul>
<li>应用数据被分割成 TCP 认为最适合发送的数据块。</li>
<li>TCP 给发送的每一个包进行编号，接收方对数据包进行排序，把有序数据传送给应用层。</li>
<li><strong>校验和</strong>：TCP 将保持它<u>首部和数据的检验和</u>。这是一个端到端的检验和，目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错，TCP 将丢弃这个报文段和不确认收到此报文段。</li>
<li>TCP 的接收端会丢弃重复的数据。</li>
<li><strong>流量控制</strong>：TCP 连接的每一方都有固定大小的缓冲空间，TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据，能提示发送方降低发送的速率，防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。 （TCP 利用滑动窗口实现流量控制）</li>
<li><strong>拥塞控制</strong>：当网络拥塞时，减少数据的发送。<ul>
<li><img class="pure-img" alt="截屏2020-12-08 15.44.37" src="https://zromyk.gitee.io/myblog-figurebed/post/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%80%83%E7%A0%94-%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E8%B7%AF.assets/%E6%88%AA%E5%B1%8F2020-12-08%2015.44.37.png" /></li>
<li><strong>慢开始：</strong> 指数规律增长</li>
<li><strong>拥塞避免：</strong>加法增大</li>
<li><strong>快重传：</strong>快重传算法规定，发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段，而不必继续等待设置的重传计时器时间到期。</li>
<li><strong>快恢复：</strong>当发送方连续收到三个重复确认（ACK）时，就执行“乘法减小”算法，把ssthresh门限减半。但是接下去并不执行慢开始算法。</li>
</ul>
</li>
<li><strong>停止等待协议</strong>：也是为了实现可靠传输的，它的基本原理就是每发完一个分组就- 停止发送，等待对方确认。在收到确认后再发下一个分组。 超时重传： 当 TCP 发出一个段后，它启动一个定时器，等待目的端确认收到这个报文段。如果不能及时收到一个确认，将重发这个报文段。</li>
</ul>
<h4 id="3tcp">3、TCP拥塞控制讲一下？</h4>
<h4 id="4_8">4、进程通信的方式？</h4>
<p><a href="https://blog.csdn.net/zhaohong_bo/article/details/89552188">进程间通讯的7种方式</a></p>
<ol>
<li><strong>无名管道( pipe )</strong>：管道是一种半双工的通信方式，<u>数据只能单向流动</u>，而且<u>只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。</u></li>
<li><strong>有名管道 ( FIFO )</strong> ：有名管道也是半双工的通信方式，但是它允许无亲缘关系进程间的通信。<a href="https://blog.csdn.net/hyklose/article/details/80419450?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&amp;dist_request_id=&amp;depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control">Linux 进程间通信基础（四）&ndash;fifo管道</a></li>
<li><strong>消息队列( message queue )</strong> ： 消息队列是由消息的链表，存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。</li>
<li><strong>信号量( semophore )</strong> ： 信号量是一个计数器，可以用来控制多个进程对共享资源的访问。它常作为一种锁机制，防止某进程正在访问共享资源时，其他进程也访问该资源。因此，主要作为进程间以及同一进程内不同线程之间的同步手段。</li>
<li><strong>信号( sinal )</strong> ： 信号是一种比较复杂的通信方式，用于通知接收进程某个事件已经发生。</li>
<li><strong>共享内存( shared memory )</strong> ：共享内存就是映射一段能被其他进程所访问的内存，这段共享内存由一个进程创建，但多个进程都可以访问。共享内存是最快的 IPC 方式，它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制，如信号两，配合使用，来实现进程间的同步和通信。</li>
<li><strong>套接字( socket )</strong> ： 套解口也是一种进程间通信机制，与其他通信机制不同的是，它可用于不同机器间的进程通信。</li>
</ol>
<h4 id="5socketclientserver">5、socket中的client和server讲一下？</h4>
<h4 id="6_2">6、描述一下在浏览器输入网址后背后发生的所有流程？</h4>
<p><strong>简单路径线</strong>：</p>
<ol>
<li>键盘或触屏输入URL并回车确认</li>
<li>URL解析 / DNS解析查找域名IP地址</li>
<li>网络连接发起HTTP请求</li>
<li>HTTP报文传输过程</li>
<li>服务器接收数据</li>
<li>服务器响应请求/MVC</li>
<li>服务器返回数据</li>
<li>客户端接收数据</li>
<li>浏览器加载/渲染页面</li>
<li>打印绘制输出</li>
</ol>
<h4 id="7">7、知道正向代理和反向代理吗？</h4>
<blockquote class="content-quote">
<p>https://www.zhihu.com/question/24723688</p>
</blockquote>
<h5 id="_20">正向代理</h5>
<p>正向代理，当客户端无法访问外部资源的时候（由于诸如墙这样的原因），可以通过一个正向代理去间接地访问，所以客户端需要配置代理服务器的ip。</p>
<p>我们常说的代理也就是只正向代理，正向代理的过程，它隐藏了真实的请求客户端，服务端不知道真实的客户端是谁，客户端请求的服务都被代理服务器代替来请求，某些科学上网工具扮演的就是典型的正向代理角色。用浏览器访问http://www.google.com时，被残忍的block,于是你可以在国外搭建一台代理 服务器，让代理帮我去请求google.com，代理把请求返回的相应结构再返回给我。</p>
<p><img class="pure-img" alt="img" src="https://zromyk.gitee.io/myblog-figurebed/post/Cpp岗位面试知识.assets/v2-07ededff1d415c1fa2db3fd89378eda0_1440w.jpg" /></p>
<h5 id="_21">反向代理</h5>
<p>反向代理隐藏了真实的服务端，当我们请求 www.baidu.com 的时候，就像拨打可能有成千上万台服务器为我们服务，但具体是哪一台，你不知道，也不需要知道，你只需要知道反向代理服务器是谁就好了，www.baidu.com 就是我们的反向代理服务器，反向代理服务器会帮我们把请求转发到真实的服务器那里去。Nginx 就是性能非常好的反向代理服务器，用来做负载均衡。</p>
<ul>
<li>保证内网的安全，公网作为访问地址，web服务器谁内网</li>
<li>负载均衡</li>
</ul>
<p><img class="pure-img" alt="img" src="https://zromyk.gitee.io/myblog-figurebed/post/Cpp岗位面试知识.assets/v2-816f7595d80b7ef36bf958764a873cba_1440w.jpg" /></p>
<p><img class="pure-img" alt="截屏2021-03-28 11.55.55" src="https://zromyk.gitee.io/myblog-figurebed/post/Cpp岗位面试知识.assets/截屏2021-03-28 11.55.55.png" /></p>
<p>正向代理中，proxy 和 client 同属一个LAN, 对 server 透明 ;<br />
反向代理中，proxy 和 server 同属一个LAN，对 client 透明。<br />
实际上 proxy 在两种代理中做的事都是代为收发请求和响应，不过从结构上来看正好左右互换了下，所以把后出现的那种代理方式叫成了反向代理。</p>
</div>
<div id="nav">
  <div class="navigation">
  <ul class="pure-menu-list">
    <li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 0.75em;" href="#_1">语言基础</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#cc">C/C++语言基础</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1-cccc">1. C++语言特点、C++语言特点、C和C++的区别</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2">2. 头文件、变量、指针、运算符、数组、函数、结构体、传值方式</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3-staticconst-nullptr-define">3. static、const、 nullptr、 ++、 define</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#4-new-malloc">4. new 和 malloc 区别</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#c">C++内存管理</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1_1">1. 堆、栈、常量区</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2_1">2. 内存泄露</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3">3. 内存对齐</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#4-c">4. C++中一个类占用的内存字节</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#_2">面向对象</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1_2">1. 面向对象的理解</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2_2">2. 重载和重写</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3_1">3. 构造函数、深拷贝和浅拷贝</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#4_1">4. 继承、多继承、菱形继承</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#5_1">5. 多态、虚函数</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#c_1">C++ 多态的实现及原理</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#_3">虚函数指针</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#_4">虚基类</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#_5">纯虚函数与抽象类</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#6-this">6. this 指针</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#this">this指针的特征：</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#__thiscall">__thiscall的调用特点：</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#6-c">6. C++中内存泄漏的几种情况</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#1-new-delete">1. 在类的构造函数和析构函数中没有匹配的调用 new 和 delete 函数</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#2_3">2. 没有正确地清除嵌套的对象指针</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#3-delete">3. 在释放对象数组时在delete中没有使用方括号</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#4_2">4. 指向对象的指针数组不等同于对象数组</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#5_2">5. 缺少拷贝构造函数</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#6">6. 缺少重载赋值运算符</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#7-nonmodifying">7.  关于 nonmodifying 运算符重载的常见迷思</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#8">8. 没有将基类的析构函数定义为虚函数</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#boost">Boost</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#stl">STL</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1-stl">1. STL基本组成部分</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2-stl">2. STL常见容器</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3-stl">3. STL常见容器的原理</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#c_2">c++</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1_3">1.智能指针</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#auto_ptr">auto_ptr</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#uniqueptrautoptr">unique<em>ptr（替换auto</em>ptr）</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#shared_ptr">shared_ptr</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#weak_ptr">weak_ptr</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#weak_ptr_1">测试 <span style="overflow-x: auto; max-width:100%; display:inline;"><code>weak_ptr</code></span> 常用函数的用法</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#_6">对全部三种智能指针都应避免的一点：</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2-c11">2. 右值引用（C++11）</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#_7">左值、右值</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3_2">3. 类型转换</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#static_cast">static_cast</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#reinterpret_cast">reinterpret_cast</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#const_cast">const_cast</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#dynamic_cast">dynamic_cast</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#4-lambda">4. Lambda</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#_8">操作系统基础</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1-linux">1. Linux常见命令</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2_4">2. 文件权限</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3_3">3. 软链接和硬链接</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#_9">符号链接（软链接）</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#_10">硬链接</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#4_3">4. 静态库和动态库</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#_11">静态库</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#_12">动态库</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#5_3">5. 虚拟地址空间</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#linux_2">Linux开发基础</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1-makefile">1. Makefile</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2-gdb">2. GDB调试</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3-api">3. 基本的API</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#linux_3">Linux多线程</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#_13">进程和线程的区别</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1_4">1. 井程状态、并行和并发</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2_5">2. 瓜儿进程、僵尸进程</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3_4">3. 进程间通信的几种方式</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#4_4">4. 有名管道、匿名管道</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#5_4">5. 内存映射、 定时器、信号、守护进程</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#linux_4">Linux网络编程</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1-macip">1. MAC地址、IP地址、 端口、协议</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2_6">2. 网络参考模型</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3_5">3. 字节序、字节序转换函数</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#4-ip">4. IP地址转换函数</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#5-socket">5. socket地址</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#tcp">TCP协议</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1-tcp">1. TCP协议头</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2_7">2. 三次握手</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3_6">3. 四次挥手</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#4_5">4. 滑动窗口</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#5-tcp">5. TCP状态转换</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#6_1">6. 半关闭、端口复用</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#_14">多路复用</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1-i0">1. 几种I0模型</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#1io">（1）阻塞IO</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#2io">（2）非阻塞IO模型</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#3io">（3）多路复用IO模型</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#4io">（4）信号驱动IO模型</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#5io">（5）异步IO模型</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2-select">2. select</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3-poll">3. poll</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#4-epoll">4. epoll</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#5-reactor-proactor">5. Reactor 和 Proactor 模式</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#_15">数据库</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1-mysql">1. MySQL索引</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#mysqlb">为什么mysql索引用B+树而不用哈希表？</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2-mysql">2. MySQL事务</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3_7">3. 数据库的锁</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#_16">设计模式</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1_5">1. 单例设计模式</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2_8">2. 懒汉式和饿汉式</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3_8">3. 厂设计模式</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#4_6">4. 装饰设计模式</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#5_5">5. 观察者设计模式</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#_17">垃圾回收</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#_18">有向可达图与根集</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1_6">1. 引用计数算法</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2-mark-sweep">2. Mark &amp; Sweep （标记清除算法）</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3_9">3. 节点复制算法</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#4_7">4. 分代回收</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.25em;" href="#_19">计算机网络</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#1tcpip">1、TCP/IP五层模型？</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#2tcp">2、TCP怎么保证可靠传输？</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#3tcp">3、TCP拥塞控制讲一下？</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#4_8">4、进程通信的方式？</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#5socketclientserver">5、socket中的client和server讲一下？</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#6_2">6、描述一下在浏览器输入网址后背后发生的所有流程？</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 1.75em;" href="#7">7、知道正向代理和反向代理吗？</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#_20">正向代理</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" style="padding:0.1em 0em 0.1em 2.25em;" href="#_21">反向代理</a>
</li>

  </ul>
</div>

</div>
 
    </div>
  </div>
  <div id="footer">
    <div class="legal pure-g">
  <div class="pure-u-1 u-sm-1-2">
    <p class="legal-license"><a href="https://beian.miit.gov.cn/#/Integrated/index">浙ICP备2020038748号</a></p>
  </div>
  <div class="pure-u-1 u-sm-1-2">
    <p class="legal-links"><a href="https://github.com/zromyk">GitHub</a></p>
    <p class="legal-copyright">Copyright © 2020 Wei Zhou. 保留所有权利。</p>
  </div>
</div>
  </div>
</body>
</html>
